package com.cantor.provider.start;

import com.cantor.core.handler.CantorMessageCodec;
import com.cantor.core.handler.StickAndHalfPackageDecoder;
import com.cantor.core.pool.CantorExecutorPool;
import com.cantor.provider.handler.AsyncCantorRequestMessageHandler;
import com.cantor.provider.handler.PingHandler;
import com.cantor.provider.regsitry.ServiceRegistrant;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

/**
 * Provider的单个netty服务器
 */
@Slf4j
public class ProviderNettyKeeper {

    // 网卡地址
    private String host;

    // 端口
    private Integer port;

    // 服务注册者
    private ServiceRegistrant serviceRegistrant;

    // 构造函数
    public ProviderNettyKeeper(String host, Integer port, ServiceRegistrant serviceRegistrant) {
        this.host = host;
        this.port = port;
        this.serviceRegistrant = serviceRegistrant;
    }

    public boolean run() {
        // Prepare two groups.
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        ChannelFuture channelFuture = null;
        try {
            // Prepare all handlers
            final AsyncCantorRequestMessageHandler IN_REQUEST_HANDLER = new AsyncCantorRequestMessageHandler(serviceRegistrant);  // 新的处理器(非阻塞版)
            final PingHandler IN_PING_HANDLER = new PingHandler(); // ping心跳处理(负责接收ping和接收读空闲事件)
            // Run the server.
            channelFuture = new ServerBootstrap().group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 256)
                    .option(ChannelOption.TCP_NODELAY,true)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childOption(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(65535))
                    .childOption(ChannelOption.TCP_NODELAY, true) // 不等大包, 立即发包
                    .childHandler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel ch) {
                            ChannelPipeline pipeline = ch.pipeline();
                            // Duplex
                            // pipeline.addLast(new LoggingHandler()); // 日志
                            pipeline.addLast(new IdleStateHandler(10L,0,0, TimeUnit.SECONDS)); // 空闲检测器
                            pipeline.addLast(new CantorMessageCodec()); // 编解码器
                            // Out

                            // In
                            pipeline.addLast(new StickAndHalfPackageDecoder()); // 半包黏包处理器
                            pipeline.addLast(IN_PING_HANDLER); // 心跳包处理
                            pipeline.addLast(IN_REQUEST_HANDLER); // 业务处理器

                        }
                    })
                    .bind(host,port)
                    .addListener(f -> {
                        if (f.isSuccess()) {
                            log.info("provider netty is running at {}:{}...", host,port);
                        }
                    }).sync();
            return channelFuture.isSuccess();
        } catch (InterruptedException e) {
            e.printStackTrace();
            log.error(e.getMessage());
            return false;
        } finally {
            // 未来关闭
            ChannelFuture finalChannelFuture = channelFuture;
            CantorExecutorPool.execute(() -> {
                try {
                    if (null != finalChannelFuture) {
                        finalChannelFuture.channel().closeFuture().sync();
                        bossGroup.shutdownGracefully();
                        workerGroup.shutdownGracefully();
                        log.info("BossGroup与WorkerGroup已经优雅关闭");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    log.error("Provider端的Netty关闭出现异常");
                }
            });
        }
    }
}

